﻿using Iot.Device.Gpio.Drivers;
using IotDeviceToolHepler.Model.Constant;
using IotDeviceToolHepler.WiringOPSharp;
using System;
using System.Collections.Generic;
using System.Device.Gpio;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IotDeviceToolHepler.Utils
{
    /// <summary>
    /// 香橙子调用WiringOP操作gpio Output 高低电平
    /// </summary>
    public class UtilsOrangePiGpio
    {
        //运行调用例子
        public void test()
        {

            Console.WriteLine("输入引脚WPI编号");
            //控制台中输入内容
            int pinNum = int.Parse(Console.ReadLine());
            Console.WriteLine("输入o打开，输入c关闭");
            string command = Console.ReadLine();
            if (!string.IsNullOrWhiteSpace(command))
            {
                //setGpioOutputMode(command, pinNum);
            }

        }
        /// <summary>
        /// pin输入高电平或低电平
        /// </summary>
        /// <param name="command">open/close</param>
        /// <param name="pinNum">wpi编号</param>
        /// <returns>状态</returns>
        public string setGpioOutputMode(string command, int pinNum)
        {

            try
            {
                Setup.WiringPiPiSetup();
                GPIO.PinMode(pinNum, WiringPi.Output);

                if (command == "open")
                {   //open

                    GPIO.DigitalWrite(pinNum, WiringPi.High);
                    //Console.WriteLine("执行开");
                    return ConstantGpio.GpioPinOpen;
                }
                else if (command == "close")
                {   //close

                    GPIO.DigitalWrite(pinNum, WiringPi.Low);
                    // Console.WriteLine("执行关");
                    return ConstantGpio.GpioPinClose;
                }

                return ConstantGpio.GpioPinError;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return ConstantGpio.GpioPinError;
            }
        }
        /// <summary>
        /// 获取引脚输出状态：高电平或低电平状态
        /// </summary>
        /// <param name="pinNum">wpi引脚编号</param>
        /// <returns>返回状态</returns>
        public string getGpioOutputMode(int pinNum)
        {
            try
            {
                Setup.WiringPiPiSetup();
                GPIO.PinMode(pinNum, WiringPi.Output);
                int value = GPIO.DigitalRead(pinNum);
                if (value == WiringPi.High)
                {
                    //Console.WriteLine("获得状态 开");
                    return ConstantGpio.GpioPinOpen;
                }
                else if (value == WiringPi.Low)
                {

                    // Console.WriteLine("获得状态  关");
                    return ConstantGpio.GpioPinClose;
                }
                return ConstantGpio.GpioPinError;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return ConstantGpio.GpioPinError;
            }
        }

        private static object obj = new object();
        /// <summary>
        /// 获取引脚输入状态：高电平或低电平状态
        /// </summary>
        /// <param name="pinNum">wpi引脚编号</param>
        /// <returns>返回状态</returns>
        public static string getGpioInputMode(int pinNum)
        {
            lock (obj)
            {
                try
                {
                    Setup.WiringPiPiSetup();
                    GPIO.PinMode(pinNum, WiringPi.Input);
                    GPIO.PullUpDnControl(pinNum, WiringPi.PudDown);
                    int value = GPIO.DigitalRead(pinNum);
                    if (value == WiringPi.High)
                    {
                        //Console.WriteLine("获得状态 开");
                        return ConstantGpio.GpioPinOpen;
                    }
                    else if (value == WiringPi.Low)
                    {

                        // Console.WriteLine("获得状态  关");
                        return ConstantGpio.GpioPinClose;
                    }
                    return ConstantGpio.GpioPinError;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    return ConstantGpio.GpioPinError;
                }
            }
        }

        /// <summary>
        /// 微软库操作 gpio
        /// </summary>
        /// <param name="pin"></param>
        /// <param name="pinValue"></param>
        public void setGpioOutValue_GpioController(int pin, PinValue pinValue)
        {

            GpioController gpioController = new GpioController();
            if (gpioController.IsPinOpen(pin))
            {
                if (gpioController.GetPinMode(pin) != PinMode.Output)
                {
                    closeGpio_GpioController(pin);
                    gpioController.OpenPin(pin, PinMode.Output);
                }
            }
            else
            {
                gpioController.OpenPin(pin, PinMode.Output);
            }
            gpioController.Write(pin, pinValue);
        }
        /// <summary>
        /// 微软库操作 gpio
        /// </summary>
        /// <param name="pin"></param>
        /// <param name="pinValue"></param>
        public void closeGpio_GpioController(int pin)
        {
            GpioController gpioController = new GpioController();
            if (gpioController.IsPinOpen(pin))
            {
                gpioController.ClosePin(pin);
            }
        }
        /// <summary>
        /// 回调监听,1、开机后不能重复运行方法，会导致第二次运行监听无效，可能是第一次监听占用中2、实验证明，只能监听一个引脚，两个会报错
        /// </summary>
        /// <param name="pinNum"></param>
        public void GpioListen_GpioController(int pinNum)
        {
            GpioController gpioController = new GpioController();
            if (gpioController.IsPinOpen(pinNum))
            {
                if (gpioController.GetPinMode(pinNum) != PinMode.Input)
                {
                    new UtilsOrangePiGpio().closeGpio_GpioController(pinNum);
                    gpioController.OpenPin(pinNum, PinMode.Input);
                }
            }
            else
            {
                gpioController.OpenPin(pinNum, PinMode.Input);
            }
            gpioController.RegisterCallbackForPinValueChangedEvent(pinNum, PinEventTypes.Rising, callbackGpioListen);
            //PinEventTypes.Rising 高电平触发
            //PinEventTypes.Falling 低电平时触发
            //gpioController.UnregisterCallbackForPinValueChangedEvent(pinNum, callback);//取消监听
        }

        public void callbackGpioListen(object sender, PinValueChangedEventArgs pinValueChangedEventArgs)
        {
            Console.WriteLine(" 回调 " + pinValueChangedEventArgs.PinNumber + "--" + pinValueChangedEventArgs.ChangeType + "-" + System.DateTime.Now);
        }




        /// <summary>
        ///  监听gpio高低电平变化
        /// </summary>
        /// <param name="pinNum"></param>
        /// <param name="intervalMinSecond">默认100毫秒检查一次状态</param>
        public void gpioListenAsync_WiringPi(int pinNum,  int intervalMinSecond = 100)
        {
            Task.Run(() =>
            {
                string oldState = "";
                while (true)
                {
                    string getState =  UtilsOrangePiGpio.getGpioInputMode(pinNum);
                    if (oldState != getState)
                    {
                        oldState = getState;

                        callbackGpioListen_WiringPi(pinNum, getState);
                    }
                    Thread.Sleep(intervalMinSecond);
                }
            });
        }

        public void callbackGpioListen_WiringPi(int PinNumber, string state)
        {
            Console.WriteLine(" 回调 " + PinNumber + "-" + state + "-" + System.DateTime.Now);
        }
    }
}
